package com.yc.cinema.mybatis;


//reflect  反射

import org.apache.ibatis.annotations.Select;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Sqlsession {
    public <T> T getMapper(Class<T> clss) {
        //基于JDK动态代理
        //InvocationHandler  方法拦截器
        final Object o = Proxy.newProxyInstance(
                clss.getClassLoader(),//类加载器
                new Class[]{clss},//类接口数组
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                        System.out.println("proxy = " + proxy);
                        System.out.println("method = " + method);
                        System.out.println("args = " + Arrays.toString(args));

                        //使用反射获取方法上的注解
                        Select select = method.getAnnotation(Select.class);
                        //sql语句
                        String[] value = select.value();
                        String sql = value[0];
                        //提取sql中的参数值
                        int index = 0;
                        //参数集合
                        List<Object> params = new ArrayList<>();
                        while ((index =  sql.indexOf("#{")) > -1) {
                            //查找右
                            int endIndex = sql.indexOf("}",index);
                            String name = sql.substring(index + 2,endIndex);
                            //提取方法参数中的指定的name值
                            //如果方法只有一个 简单数据类型（或String）参数
                            if (method.getParameters().length == 1){
                                //单个参数
                                Parameter parameter = method.getParameters()[0];
                                if (parameter.getType().isPrimitive()
                                        || parameter.getType() == String.class
                                        //||  包装器类型 Integer
                                ){
                                    //如果方法只有一个  简单基本数据类型(或String)参数
                                    params.add(args[0]);
                                }else{
                                    //否则就是对象参数  Hall,Movie
                                    //通过反射获取属性值
                                    Field field = args[0].getClass().getField(name);
                                    field.setAccessible(true); //设置强制访问,private
                                    Object val = field.get(args[0]);  //获取字段值
                                    params.add(val);
                                }
                            } else{
                                //多个参数  ,遍历每个参数的注解 ，提取参数值
                                //拓展

                            }
                            index = endIndex + 1;
                        }
                        System.out.println("params = " + params);
                        //将sql 中的#{...}  替换成？
                        sql = sql.replaceAll("#\\{\\w+\\}", "?");
                        System.out.println("sql = " + sql);

                        //DBHelper  执行查询 ,语句sql,参数数组：params.toArray()
                        //Map<String,Object>  map = DBHelper.selectOneMap(sql,params.toArray())

                        //通过反射获取返回值类型
                        Class<?> returnType = method.getReturnType();  //Hall ret = new Hall()
                        //只实现 单个对象返回
                        Object ret = returnType.newInstance();

                        Map<String,Object> map = null;

                        map.entrySet().forEach((entry)->{
                            try {
                                //entry.getKey();  字段名
                                //entry.getValue();  字段值
                                Field field = ret.getClass().getField(entry.getKey());
                                field.setAccessible(true); //设置强制访问,private
                                field.set(ret,entry.getValue());//设置字段值
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        });

                        return null;
                    }
                });
        return (T) o;
    }
}
